<script lang="ts" setup>
import { apiMenu } from "@/api/sys";
import { useMessage } from "@/hooks/web/use-message";
import { AdvancedFilter, Comparator, MenuBehavior, MenuType, type AdvancedSearch, type MenuInfo } from "@/models";
import options from "@/models/disable-options.json";
import { generateAuditColumns, listToTree } from "@/utils";
import { computed, onMounted, reactive, ref } from "vue";
import type { VxeGridInstance, VxeGridProps } from "vxe-table";
import Delete from "~icons/ep/delete";
import Edit from "~icons/ep/edit";
import Plus from "~icons/ep/plus";
import Refresh from "~icons/ep/refresh";
import Search from "~icons/ep/search";
import editMenuVue from "./edit-menu.vue";
import editParentVue from "./edit-parent.vue";

const { 子系统, 目录, 页面 } = MenuType;
const { LIKE } = Comparator;
const { confirmDelete } = useMessage();
const hasChecked = computed(() => !!gridRef.value?.getCheckboxRecords(true).length);

//#region [grid]
const gridRef = ref<VxeGridInstance>();
const gridQuery = reactive<{ keyword?: string; disabled?: boolean }>({});
const gridOption = reactive<VxeGridProps<MenuInfo>>({
  autoResize: true,
  size: "small",
  border: "full",
  showOverflow: "ellipsis",
  columnConfig: { resizable: true, minWidth: 60 },
  rowConfig: { keyField: "id" },
  toolbarConfig: { slots: { buttons: "toolbar_buttons" } },
  treeConfig: {},
  columns: [
    { type: "checkbox", field: "title", title: "标题", treeNode: true, slots: { default: "field_title" } },
    { field: "type", title: "类型", width: 120, formatter: ({ cellValue }) => MenuType[cellValue] },
    { field: "code", title: "编码", titlePrefix: { content: "菜单关联页面对象的唯一标识" } },
    {
      field: "path",
      title: "路径",
      titlePrefix: {
        content:
          "菜单类型为：\n" +
          "页面、目录、子系统时，表示前端路由，例如：/sys/menu\n" +
          "功能时，表示后端接口方法+路由，如：POST /menu\n" +
          "信息时，表示信息资源链接地址，如：https://baidu.com",
      },
    },
    { field: "redirect", title: "跳转地址" },
    {
      field: "behavior",
      title: "行为",
      titlePrefix: {
        content:
          "未授权菜单编码关联的页面对象的渲染行为，默认为隐藏：\n" +
          "隐藏，该对象对用户不可见\n" +
          "禁用，该对象对用户可见，但处于禁用状态\n" +
          "提示，该对象对用户可见，操作会得到无权限提示",
      },
      formatter: ({ cellValue }) => MenuBehavior[cellValue],
    },
    { field: "sortId", title: "排序", width: 80 },
    { field: "isDisabled", title: "状态", width: 80, formatter: ({ cellValue }) => (cellValue ? "禁用" : "正常") },
    ...generateAuditColumns<MenuInfo>({ dateMode: "date" }),
    { title: "操作", width: 120, align: "center", fixed: "right", slots: { default: "field_ops" } },
  ],
});
//#endregion

//#region [form]
const editRef = ref<InstanceType<typeof editMenuVue>>();
const parentRef = ref<InstanceType<typeof editParentVue>>();
//#endregion

//#region [action]
function prepareParams() {
  let keywordFilter: AdvancedFilter<MenuInfo> | undefined = undefined;
  if (gridQuery.keyword) {
    keywordFilter = new AdvancedFilter<MenuInfo>(
      {
        code: { value: gridQuery.keyword },
        title: { value: gridQuery.keyword, comparator: LIKE },
        path: { value: gridQuery.keyword, comparator: LIKE },
      },
      "OR",
    );
  }
  let disabledFilter: AdvancedFilter<MenuInfo> | undefined = undefined;
  if (gridQuery.disabled !== undefined) {
    disabledFilter = new AdvancedFilter<MenuInfo>({ isDisabled: { value: gridQuery.disabled } });
  }

  if (keywordFilter && disabledFilter) return keywordFilter.and(disabledFilter);
  if (keywordFilter || disabledFilter) return keywordFilter || disabledFilter;
  return undefined;
}
async function load() {
  gridOption.loading = true;
  const filter = prepareParams();
  const params: AdvancedSearch<MenuInfo> = { s: [{ f: "sortId", s: "ASC" }] };
  if (filter) params.f = filter;
  const response = await apiMenu.find<MenuInfo>(params);
  const tree = listToTree(response.value || []);
  gridRef.value?.clearCheckboxRow();
  gridOption.data = tree;
  gridOption.loading = false;
}
async function reset() {
  gridQuery.keyword = undefined;
  gridQuery.disabled = undefined;
  await load();
}
function addable(menu: MenuInfo) {
  return menu.type === 页面 || menu.type === 目录 || menu.type === 子系统;
}
function handleRoot() {
  editRef.value?.open();
}
function handleParent() {
  const checked: MenuInfo[] | undefined = gridRef.value?.getCheckboxRecords(true);
  if (!checked || checked.length === 0) return;

  const menus = checked.filter((m) => !checked.some((c) => c.id === m.pid)); // 挑选出需要修改父节点的菜单
  parentRef.value?.open(menus, checked);
}
function handleNew(menu: MenuInfo) {
  editRef.value?.open(undefined, menu);
}
function handleEdit(menu: MenuInfo) {
  editRef.value?.open(menu.id, gridRef.value?.getRowById(menu.pid || 0));
}
function handleDel(menu: MenuInfo) {
  confirmDelete(
    `是否删除菜单【${menu.title}(${menu.code})】及其子菜单和相关配置项？`,
    async () => {
      await apiMenu.remove(menu.id);
      await load();
    },
    { title: "删除菜单确认" },
  );
}
//#endregion

onMounted(() => {
  load();
});
</script>

<template>
  <div class="m-3">
    <el-form :inline="true">
      <el-form-item class="w-md">
        <el-input v-model="gridQuery.keyword" placeholder="请输入标题、编码或路由" clearable @keyup.enter="load" />
      </el-form-item>
      <el-form-item>
        <el-select v-model="gridQuery.disabled" class="" clearable placeholder="请选择组件状态">
          <el-option v-for="(item, index) in options" :key="index" :label="item.label" :value="item.value" />
        </el-select>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" :icon="Search" plain @click="load">搜索</el-button>
        <el-button type="primary" :icon="Refresh" plain @click="reset">重置</el-button>
      </el-form-item>
    </el-form>

    <vxe-grid ref="gridRef" :="gridOption">
      <template #toolbar_buttons>
        <el-button type="primary" :icon="Plus" plain title="新增根节点" @click="handleRoot">新增根节点</el-button>
        <el-button type="primary" :icon="Edit" plain title="设置父节点" :disabled="!hasChecked" @click="handleParent">设置父节点</el-button>
      </template>
      <template #field_title="{ row }">
        <icon-symbol v-if="!!row.icon" class="m-r-1" :name="row.icon" />
        <span v-text="row.title"></span>
      </template>
      <template #field_ops="{ row }">
        <el-button v-if="addable(row)" size="small" type="success" :icon="Plus" title="新增" @click="handleNew(row)"></el-button>
        <el-button size="small" type="warning" :icon="Edit" title="编辑" @click="handleEdit(row)"></el-button>
        <el-button size="small" type="danger" :icon="Delete" title="删除" @click="handleDel(row)"></el-button>
      </template>
    </vxe-grid>
  </div>

  <edit-menu-vue ref="editRef" @onsaved="load" />
  <edit-parent-vue ref="parentRef" @onsaved="load" />
</template>

<style lang="scss" scoped>
.el-button--small {
  padding: 5px;
}
</style>
